package com.example.nsddemo

import android.content.Context
import android.content.Intent
import android.net.nsd.NsdManager
import android.net.nsd.NsdServiceInfo
import android.os.Build
import android.os.Bundle
import android.os.ext.SdkExtensions
import android.util.Log
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

/**
 * ServiceDiscoveryActivity - 服务发现Activity
 *
 * 该Activity负责：
 * 1. 发现网络中的NSD服务
 * 2. 显示发现的服务列表
 * 3. 提供连接到选定服务的功能
 *
 * 工作流程：
 * 1. 用户点击"开始搜索"按钮
 * 2. 启动服务发现过程
 * 3. 系统回调发现监听器，发现服务
 * 4. 对发现的服务进行解析获取详细信息
 * 5. 在UI上显示服务列表
 * 6. 用户点击服务项进行连接
 */
class ServiceDiscoveryActivity : AppCompatActivity() {

    companion object {
        private const val TAG = "ServiceDiscovery" // 日志标签，用于调试和错误追踪
        private const val SERVICE_TYPE = "_demo._tcp." // 要搜索的服务类型，必须与ServiceProviderActivity中注册的类型一致
    }

    // NSD管理器，用于发现和解析网络服务
    private lateinit var nsdManager: NsdManager

    // 服务发现监听器，处理服务发现过程中的各种事件
    private var discoveryListener: NsdManager.DiscoveryListener? = null

    // 服务解析监听器，处理服务解析过程中的各种事件
    private var resolveListener: NsdManager.ResolveListener? = null

    // UI组件
    private lateinit var toggleDiscoveryButton: Button        // 开始/停止搜索按钮
    private lateinit var discoveryStatusTextView: TextView   // 搜索状态显示文本
    private lateinit var servicesContainer: LinearLayout     // 服务列表容器

    // 已发现服务的列表，用于在UI上显示
    private val discoveredServices = mutableListOf<NsdServiceInfo>()

    // 服务发现状态标志
    private var isDiscovering = false

    /**
     * Activity创建时调用
     * 初始化UI、设置监听器、获取系统服务
     */
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_service_discovery)
        initViews() // 初始化UI组件
        setupClickListeners() // 设置按钮点击监听器
        nsdManager = getSystemService(Context.NSD_SERVICE) as NsdManager // 获取NSD管理器系统服务
        initializeListeners() // 初始化服务发现和解析监听器
    }

    /**
     * 初始化UI组件
     * 获取布局中的各个控件引用并初始化显示状态
     */
    private fun initViews() {
        toggleDiscoveryButton = findViewById(R.id.toggleDiscoveryButton)
        discoveryStatusTextView = findViewById(R.id.discoveryStatusTextView)
        servicesContainer = findViewById(R.id.servicesContainer)

        // 初始化UI显示状态
        updateUI()
    }

    /**
     * 设置按钮点击监听器
     * 根据当前发现状态切换开始/停止搜索功能
     */
    private fun setupClickListeners() {
        toggleDiscoveryButton.setOnClickListener {
            // 如果正在发现服务，则停止发现；否则开始发现服务
            if (isDiscovering) {
                stopDiscovery()
            } else {
                startDiscovery()
            }
        }
    }

    /**
     * 开始服务发现
     * 启动网络服务发现过程
     */
    private fun startDiscovery() {
        // 如果已经在发现服务，则直接返回
        if (isDiscovering) return

        try {
            // 启动服务发现过程
            nsdManager.discoverServices(
                SERVICE_TYPE,                   // 要搜索的服务类型
                NsdManager.PROTOCOL_DNS_SD,     // 使用DNS-SD协议
                discoveryListener               // 发现监听器
            )

            discoveredServices.clear()          // 清空之前发现的服务列表
            updateServiceList()                 // 更新服务列表显示
            isDiscovering = true                // 更新发现状态
            updateUI()                          // 更新UI显示
            Toast.makeText(this, "开始搜索服务...", Toast.LENGTH_SHORT).show()
        } catch (e: Exception) {
            // 处理启动服务发现失败情况
            Log.e(TAG, "启动服务发现失败", e)
            Toast.makeText(this, "启动服务发现失败: ${e.message}", Toast.LENGTH_SHORT).show()
        }
    }

    /**
     * 停止服务发现
     * 停止网络服务发现过程
     */
    private fun stopDiscovery() {
        // 只有在正在发现服务时才执行停止操作
        if (isDiscovering) {
            try {
                nsdManager.stopServiceDiscovery(discoveryListener)  // 停止服务发现过程
                isDiscovering = false                               // 更新发现状态
                updateUI()                                          // 更新UI显示
                Toast.makeText(this, "已停止搜索", Toast.LENGTH_SHORT).show()
            } catch (e: Exception) {
                // 处理停止服务发现失败情况
                Log.e(TAG, "停止服务发现失败", e)
                Toast.makeText(this, "停止服务发现失败: ${e.message}", Toast.LENGTH_SHORT).show()
            }
        }
    }

    /**
     * 更新UI显示
     * 根据服务发现状态更新按钮文本和状态显示
     */
    private fun updateUI() {
        try {
            // 根据发现状态设置按钮文本
            toggleDiscoveryButton.text = if (isDiscovering) "停止搜索" else "开始搜索"

            // 根据发现状态设置状态文本
            discoveryStatusTextView.text = if (isDiscovering)
                "搜索状态: 进行中"
            else
                "搜索状态: 已停止"
        } catch (e: Exception) {
            // 处理更新UI失败情况
            Log.e(TAG, "更新UI失败", e)
        }
    }

    /**
     * 更新服务列表显示
     * 在UI上显示当前发现的所有服务
     */
    private fun updateServiceList() {
        try {
            // 在主线程中更新UI
            runOnUiThread {
                // 清空服务容器中的所有视图
                servicesContainer.removeAllViews()

                // 根据服务列表是否为空显示不同内容
                if (discoveredServices.isEmpty()) {
                    // 如果没有发现服务，显示提示信息
                    val emptyView = TextView(this)
                    emptyView.text = "未发现服务"
                    emptyView.setPadding(16, 16, 16, 16)
                    servicesContainer.addView(emptyView)
                } else {
                    // 如果发现了服务，为每个服务创建显示项
                    discoveredServices.forEachIndexed { index, info ->
                        val serviceView = TextView(this)          // 创建服务显示文本
                        val ip = info.host?.hostAddress ?: "未知"         // 获取服务的IP地址，如果为空则显示"未知"
                        // 设置服务显示文本内容
                        serviceView.text = "${index + 1}. ${info.serviceName}\n地址: $ip:${info.port}"
                        // 设置内边距
                        serviceView.setPadding(16, 16, 16, 16)

                        // 设置背景色（交替显示，提高可读性）
                        serviceView.setBackgroundColor(if (index % 2 == 0) 0xFFE0E0E0.toInt() else 0xFFFFFFFF.toInt())
                        val serviceInfo = info                           // 使用局部变量保存serviceInfo，避免闭包问题
                        serviceView.setOnClickListener {                // 设置点击监听器，点击后连接到该服务
                            connectToService(serviceInfo)
                        }
                        servicesContainer.addView(serviceView)          // 将服务项添加到容器中
                    }
                }
            }
        } catch (e: Exception) {
            // 处理更新服务列表失败情况
            Log.e(TAG, "更新服务列表失败", e)
        }
    }

    /**
     * 连接到选定的服务
     * 启动通信Activity与选定的服务进行通信
     *
     * @param serviceInfo 要连接的服务信息
     */
    private fun connectToService(serviceInfo: NsdServiceInfo) {
        try {
            // 获取服务的主机地址和端口
            val host = serviceInfo.host?.hostAddress
            val port = serviceInfo.port
            val serviceName = serviceInfo.serviceName
            val serviceType = serviceInfo.serviceType
            // 获取服务属性/元数据
            val attributes = serviceInfo.attributes
            val version = attributes["version"]?.let { String(it) }
            val deviceModel = attributes["device"]?.let { String(it) }

            // 检查服务信息是否完整
            if (host != null && port != 0) {
                // 创建启动通信Activity的Intent
                val intent = Intent(this, ServiceCommunicationActivity::class.java).apply {
                    // 传递服务连接所需的信息
                    putExtra(ServiceCommunicationActivity.EXTRA_HOST, host)
                    putExtra(ServiceCommunicationActivity.EXTRA_PORT, port)
                    putExtra(ServiceCommunicationActivity.EXTRA_SERVICE_NAME, serviceName)
                    putExtra(ServiceCommunicationActivity.SERVICE_TYPE, serviceType)
                    putExtra(ServiceCommunicationActivity.SERVICE_VERSION, version)
                    putExtra(ServiceCommunicationActivity.DEVICE_MODEL, deviceModel)
                }

                // 启动通信Activity
                startActivity(intent)
            } else {
                // 服务信息不完整时提示用户
                Toast.makeText(this, "服务信息不完整", Toast.LENGTH_SHORT).show()
            }
        } catch (e: Exception) {
            // 处理连接到服务失败情况
            Log.e(TAG, "连接到服务失败", e)
            Toast.makeText(this, "连接到服务失败: ${e.message}", Toast.LENGTH_SHORT).show()
        }
    }

    /**
     * 初始化服务监听器
     * 创建并设置服务发现和解析监听器
     */
    private fun initializeListeners() {
        // 初始化服务发现监听器
        discoveryListener = object : NsdManager.DiscoveryListener {
            /**
             * 服务发现开始回调
             * @param regType 开始发现的服务类型
             */
            override fun onDiscoveryStarted(regType: String) {
                Log.d(TAG, "发现服务开始: $regType")
            }

            /**
             * 发现服务回调
             * 当发现一个匹配的服务时调用
             * @param serviceInfo 发现的服务信息
             */
            override fun onServiceFound(serviceInfo: NsdServiceInfo) {
                Log.d(TAG, "发现服务: ${serviceInfo.serviceName}, 类型: ${serviceInfo.serviceType}")

                // 只处理我们感兴趣的服务类型
                if (serviceInfo.serviceType == SERVICE_TYPE) {
                    try {
                        // 解析服务以获取详细信息（如IP地址和端口）
                        nsdManager.resolveService(serviceInfo, resolveListener)
                    } catch (e: Exception) {
                        // 处理解析服务失败情况
                        Log.e(TAG, "解析服务失败", e)
                        runOnUiThread {
                            Toast.makeText(this@ServiceDiscoveryActivity, "解析服务失败: ${e.message}", Toast.LENGTH_SHORT).show()
                        }
                    }
                }
            }

            /**
             * 服务丢失回调
             * 当一个已发现的服务不再可用时调用
             * @param serviceInfo 丢失的服务信息
             */
            override fun onServiceLost(serviceInfo: NsdServiceInfo) {
                Log.d(TAG, "服务丢失: ${serviceInfo.serviceName}")
                try {
                    // 从已发现服务列表中移除丢失的服务
                    discoveredServices.remove(serviceInfo)

                    // 更新服务列表显示
                    updateServiceList()
                } catch (e: Exception) {
                    // 处理处理服务丢失失败情况
                    Log.e(TAG, "处理服务丢失失败", e)
                }
            }

            /**
             * 服务发现停止回调
             *
             * @param serviceType 停止发现的服务类型
             */
            override fun onDiscoveryStopped(serviceType: String) {
                Log.d(TAG, "发现服务停止: $serviceType")

                // 更新发现状态
                isDiscovering = false

                // 更新UI显示
                updateUI()
            }

            /**
             * 启动发现失败回调
             * @param serviceType 服务类型
             * @param errorCode 错误代码
             */
            override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
                Log.e(TAG, "开始发现失败: $errorCode")

                // 更新发现状态
                isDiscovering = false

                // 在主线程中显示错误信息并更新UI
                runOnUiThread {
                    Toast.makeText(this@ServiceDiscoveryActivity, "发现启动失败: $errorCode", Toast.LENGTH_SHORT).show()
                    updateUI()
                }
            }

            /**
             * 停止发现失败回调
             * @param serviceType 服务类型
             * @param errorCode 错误代码
             */
            override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
                Log.e(TAG, "停止发现失败: $errorCode")

                // 在主线程中显示错误信息
                runOnUiThread {
                    Toast.makeText(this@ServiceDiscoveryActivity, "停止发现失败: $errorCode", Toast.LENGTH_SHORT).show()
                }
            }
        }

        // 初始化服务解析监听器
        resolveListener = object : NsdManager.ResolveListener {
            /**
             * 解析服务失败回调
             * @param serviceInfo 服务信息
             * @param errorCode 错误代码
             */
            override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
                Log.e(TAG, "解析服务失败: ${serviceInfo.serviceName}, 错误码: $errorCode")

                // 在主线程中显示错误信息
                runOnUiThread {
                    Toast.makeText(this@ServiceDiscoveryActivity, "解析失败: $errorCode", Toast.LENGTH_SHORT).show()
                }
            }

            /**
             * 服务解析成功回调
             * 当成功解析服务获取到详细信息时调用
             * @param serviceInfo 解析成功的服务信息
             */
            override fun onServiceResolved(serviceInfo: NsdServiceInfo) {
                Log.d(TAG, "服务解析成功: ${serviceInfo.serviceName}")
                try {
                    // 检查服务是否已经存在于列表中，避免重复添加
                    val exists = discoveredServices.any {
                        it.serviceName == serviceInfo.serviceName &&
                                it.host?.hostAddress == serviceInfo.host?.hostAddress &&
                                it.port == serviceInfo.port
                    }

                    // 如果服务不存在于列表中，则添加到列表
                    if (!exists) {
                        discoveredServices.add(serviceInfo)
                    }

                    // 更新服务列表显示
                    updateServiceList()
                } catch (e: Exception) {
                    // 处理处理服务解析结果失败情况
                    Log.e(TAG, "处理服务解析结果失败", e)
                    runOnUiThread {
                        Toast.makeText(this@ServiceDiscoveryActivity, "处理服务信息失败: ${e.message}", Toast.LENGTH_SHORT).show()
                    }
                }
            }
        }
    }

    /**
     * Activity销毁时调用
     * 清理资源，确保服务发现被正确停止
     */
    override fun onDestroy() {
        super.onDestroy()
        try {
            // 如果仍在发现服务，则停止服务发现
            if (isDiscovering) {
                nsdManager.stopServiceDiscovery(discoveryListener)
            }

            // 清理监听器引用，避免内存泄漏
            discoveryListener = null
            resolveListener = null
        } catch (e: Exception) {
            // 处理清理资源失败情况
            Log.e(TAG, "清理资源失败", e)
        }
    }
}
